package dto

import (
	"osiris/logger"
	"osiris/ocrypto/ed25519"

	"github.com/libp2p/go-libp2p/core/crypto"
)

type BlockHeader struct {

	// Timestamp 区块时间戳
	Timestamp int64 `json:"timestamp"`

	// ChainID 属于哪条链
	ChainID int `json:"chainID"`

	// Height 区块高度
	Height int64 `json:"height"`

	// PreBlockHash 上一个区块头哈希值
	PreBlockHash string `json:"preBlockHash"`

	// HeaderHash 当前区块头哈希
	HeaderHash string `json:"headerHash"`

	// AccountStateHash 账户状态树根hash
	AccountStateHash string `json:"accountStateHash"`

	// PeerStateHash 节点状态树根hash
	PeerStateHash string `json:"peerStateHash"`

	// TxHash 交易树根hash
	TxHash string `json:"txHash"`

	// ReceiptHash 收据树根hash
	ReceiptHash string `json:"receiptHash"`

	// GasUsed gas使用量
	GasUsed int `json:"gasUsed"`

	// GasLimit gas限制
	GasLimit int `json:"gasLimit"`

	// NextPeer 下一个记账节点的peer.ID.String()
	NextPeer string `json:"nextPeer"`

	// ExtraData 扩展数据
	ExtraData map[string]string `json:"extraData"`
}

func (header BlockHeader) Hash() (string, error) {
	header.HeaderHash = ""
	return SHA256Hash(header)
}

type BlockDto struct {
	BaseDto
	BlockHeader              //区块头
	Txs             []TxData `json:"txs"`             //交易列表
	WriterPeerID    string   `json:"writerPeerID"`    //记账节点的peer.ID.String()
	WriterSignature string   `json:"writerSignature"` //记账节点对DtoHash的签名
}

func (blockDto BlockDto) Hash() (string, error) {
	blockDto.DtoHash = ""
	blockDto.WriterSignature = ""
	return SHA256Hash(blockDto)
}

func (blockDto *BlockDto) HashAndSign() {
	//计算header的BlockHash
	headerHash, err1 := blockDto.BlockHeader.Hash()
	if err1 != nil {
		logger.Error(map[string]interface{}{"[dto] [BlockDto.HashAndSign()] calculate header hash": err1})
	}
	blockDto.BlockHeader.HeaderHash = headerHash

	//计算BlockDto的DtoHash
	dtoHash, err2 := blockDto.Hash()
	if err2 != nil {
		logger.Error(map[string]interface{}{"[dto] [BlockDto.HashAndSign()] calculate dto hash": err2})
	}
	blockDto.DtoHash = dtoHash

	//计算节点签名
	sig, err3 := ed25519.ED25519Sign(ed25519.GetPeerPrivKey(), blockDto.DtoHash)
	if err3 != nil {
		logger.Error(map[string]interface{}{"[dto] [BlockDto.HashAndSign()] ed25519.ED25519Sign()": err3})
	}
	blockDto.WriterSignature = sig
}

func (blockDto BlockDto) Verify(pubKey crypto.PubKey) bool {
	//计算header Hash
	headerHash, err1 := blockDto.BlockHeader.Hash()
	if err1 != nil {
		logger.Warn(map[string]interface{}{"[dto] [Verify Block] calculate header hash": err1})
		return false
	}

	//验证DtoHash
	if headerHash != blockDto.BlockHeader.HeaderHash {
		logger.Warn(map[string]interface{}{"[dto] [Verify Block] verify headedr hash": "fail"})
		return false
	}

	//TODO 如果不认识记账节点执行bootstrap

	//拿签名
	decodedSignature, err3 := ed25519.StrToED25519Sig(blockDto.WriterSignature)
	if err3 != nil {
		logger.Warn(map[string]interface{}{"[dto] [Verify Block] decode signature by base64": err3})
		return false
	}

	//验证签名
	valid := ed25519.ED25519Verify(pubKey, blockDto.DtoHash, decodedSignature)
	if !valid {
		logger.Warn(map[string]interface{}{"[dto] [Verify Block] verify sigature": "fail"})
		return false
	}

	return true
}

type BlockchainDto struct {
	BaseDto
	Blocks []BlockDto `json:"blocks"`
}
